!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 module passive_tracer_tools

!BOP
! !MODULE: passive_tracer_tools

! !DESCRIPTION:
!  This module provides support for passive tracers.
!  Subroutines in this module can be called by individual tracer modules.

! !REVISION HISTORY:
!  SVN:$Id:$

! !USES:

   use kinds_mod
   use constants, only: c0, c1, char_blank, blank_fmt
   use domain_size, only: nx_global, ny_global
   use domain, only: nblocks_clinic
   use exit_mod, only: sigAbort, exit_POP
   use communicate, only: my_task, master_task
   use constants, only: char_blank, field_loc_center, field_type_scalar
   use prognostic, only: tracer_field
   use io_tools, only: document
   use io, only: data_set
   use io_types, only: datafile, io_dim, io_field_desc, rec_type_dbl, &
       construct_file, construct_io_dim, construct_io_field, &
       destroy_file, destroy_io_field, stdout
   use prognostic, only: curtime, oldtime

   implicit none
   private
   save

! !PUBLIC TYPES:

   type, public :: ind_name_pair
      integer(int_kind) :: ind
      character(char_len) :: name
   end type

!-----------------------------------------------------------------------
!  derived type for reading tracers from a file
!-----------------------------------------------------------------------

   type, public :: tracer_read
      character(char_len) :: mod_varname, filename, file_varname, file_fmt
      real(r8) :: scale_factor, default_val
   end type

!-----------------------------------------------------------------------
!  monthly forcing variables
!-----------------------------------------------------------------------

   type, public :: forcing_monthly_every_ts
      type(tracer_read) :: input
      logical(log_kind) :: has_data
      real(r8), dimension(:,:,:,:,:), pointer :: DATA
      character(char_len) :: &
         interp_type,          & ! = 'linear'
         data_type,            & ! = 'monthly-calendar'
         interp_freq,          & ! = 'every-timestep'
         filename,             & ! = 'not-used-for-monthly'
         data_label              ! = 'not-used-for-monthly'
    real(r8), dimension(12) :: &
         data_time               ! times where DATA is given
    real(r8), dimension(20) :: &
         data_renorm             ! not used for monthly
    real(r8) :: &
         data_inc,             & ! not used for monthly data
         data_next,            & ! time that will be used for the next
                                 ! value of forcing data that is needed
         data_update,          & ! time when the a new forcing value
                                 ! needs to be added to interpolation set
         interp_inc,           & ! not used for 'every-timestep' interp
         interp_next,          & ! not used for 'every-timestep' interp
         interp_last             ! not used for 'every-timestep' interp
    integer(int_kind) :: &
         data_time_min_loc       ! index of the third dimension of data_time
                                 ! containing the minimum forcing time
  end type forcing_monthly_every_ts

! !PUBLIC MEMBER FUNCTIONS:

   public ::                                 &
      init_forcing_monthly_every_ts,         &
      file_read_tracer_block,                &
      rest_read_tracer_block,                &
      read_field

!EOP
!BOC

   interface read_field
      module procedure read_field_2D,        &
                       read_field_3D
   end interface

!EOC
!***********************************************************************

 contains

!***********************************************************************
!BOP
! !IROUTINE: init_forcing_monthly_every_ts(var)
! !INTERFACE:

 subroutine init_forcing_monthly_every_ts(var)

! !DESCRIPTION:
!  initialize fields of a variable of type forcing_monthly_every_ts
!
! !REVISION HISTORY:
!  same as module

! !OUTPUT PARAMETERS:

   type(forcing_monthly_every_ts), intent(out) :: var

!EOP
!BOC
!-----------------------------------------------------------------------

   var%interp_type = 'linear'
   var%data_type   = 'monthly-calendar'
   var%interp_freq = 'every-timestep'
   var%filename    = 'not-used-for-monthly'
   var%data_label  = 'not-used-for-monthly'

!-----------------------------------------------------------------------
!EOC

 end subroutine init_forcing_monthly_every_ts

!***********************************************************************
!BOP
! !IROUTINE: name2ind
! !INTERFACE:

 function name_to_ind(name, ind_name_table)

! !DESCRIPTION:
!  translate string into a tracer index
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

   character(char_len), intent(in) :: name

   type(ind_name_pair), dimension(:), intent(in) :: ind_name_table

! !OUTPUT PARAMETERS:

   integer(int_kind) :: name_to_ind

!EOP
!BOC
!-----------------------------------------------------------------------
!  local variables
!-----------------------------------------------------------------------

   integer(int_kind) :: i

!-----------------------------------------------------------------------

   do i = 1,size(ind_name_table)
      if (trim(name) == trim(ind_name_table(i)%name)) then
         name_to_ind = ind_name_table(i)%ind
         return
      end if
   end do

   name_to_ind = 0

!-----------------------------------------------------------------------
!EOC

 end function name_to_ind

!***********************************************************************
!BOP
! !IROUTINE: rest_read_tracer_block
! !INTERFACE:

 subroutine rest_read_tracer_block(fmt, filename, tracer_d_module, &
    TRACER_MODULE)

! !DESCRIPTION:
!  read from a restart file all tracers for a tracer module
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

   character (*), intent(in) ::  &
      fmt,                 & ! format (bin or nc)
      filename               ! file name for restart file

   type (tracer_field), dimension(:), intent(in) :: &
      tracer_d_module   ! descriptors for each tracer

! !INPUT/OUTPUT PARAMETERS:

   real(r8), dimension(:,:,:,:,:,:), intent(inout) :: &
      TRACER_MODULE     ! tracers to be read in

!EOP
!BOC
!-----------------------------------------------------------------------
!  local variables
!-----------------------------------------------------------------------

   character(*), parameter :: &
      subname = 'passive_tracer_tools:rest_read_tracer_block'

   integer (int_kind) :: &
      n               ! tracer index

   character (char_len) ::  &
      fieldname       ! tracer name temporaries

!-----------------------------------------------------------------------

   call document(subname, 'reading tracer block from ' /&
                       &/ trim(filename))

   do n=1,size(tracer_d_module)

      fieldname = char_blank
      fieldname = trim(tracer_d_module(n)%short_name) /&
               &/ '_CUR'

      call read_field(fmt, filename, fieldname, TRACER_MODULE(:,:,:,n,curtime,:))

      fieldname = char_blank
      fieldname = trim(tracer_d_module(n)%short_name) /&
               &/ '_OLD'

      call read_field(fmt, filename, fieldname, TRACER_MODULE(:,:,:,n,oldtime,:))

   end do

!-----------------------------------------------------------------------
!EOC

 end subroutine rest_read_tracer_block

!***********************************************************************
!BOP
! !IROUTINE: file_read_tracer_block
! !INTERFACE:

 subroutine file_read_tracer_block(init_filename_fmt, init_filename, &
   tracer_d_module, ind_name_table, tracer_init_ext, TRACER_MODULE)

! !DESCRIPTION:
!  read from a file all tracers for a tracer module
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

   character (*), intent(in) ::  &
      init_filename_fmt,   & ! format (bin or nc)
      init_filename          ! default filename

   type (tracer_field), dimension(:), intent(in) :: &
      tracer_d_module        ! descriptors for each tracer

   type(tracer_read), dimension(:), intent(in) :: &
      tracer_init_ext        ! namelist variable for initializing tracers

   type(ind_name_pair), dimension(:) :: &
      ind_name_table

! !INPUT/OUTPUT PARAMETERS:

   real(r8), dimension(:,:,:,:,:,:), intent(inout) :: &
      TRACER_MODULE          ! tracers to be read in

!EOP
!BOC
!-----------------------------------------------------------------------
!  local variables
!-----------------------------------------------------------------------

   character(*), parameter :: &
      subname = 'passive_tracer_tools:file_read_tracer_block'

   integer (int_kind) :: &
      tracer_cnt,   & ! number of tracers in module
      ind,          & ! tracer index for tracer name from namelist
      iblock,       & ! index for looping over blocks
      n               ! tracer index

   type(tracer_read), dimension(:), allocatable :: &
      tracer_init_int ! namelist variable for initializing tracers

   type (datafile) ::    &
      in_file         ! data file type for init ts file

!-----------------------------------------------------------------------

   tracer_cnt = size(tracer_d_module)

!-----------------------------------------------------------------------
!  initialize internal tracer_init array
!-----------------------------------------------------------------------

   allocate(tracer_init_int(tracer_cnt))
   do n = 1,tracer_cnt
      tracer_init_int(n)%mod_varname  = tracer_d_module(n)%short_name
      tracer_init_int(n)%filename     = init_filename
      tracer_init_int(n)%file_varname = tracer_d_module(n)%short_name
      tracer_init_int(n)%scale_factor = c1
      tracer_init_int(n)%default_val  = c0
      tracer_init_int(n)%file_fmt     = init_filename_fmt
   end do

!-----------------------------------------------------------------------
!  copy non-default values from external tracer_init array
!-----------------------------------------------------------------------

   do n = 1,tracer_cnt
      if (trim(tracer_init_ext(n)%mod_varname) /= 'unknown') then
         ind = name_to_ind(tracer_init_ext(n)%mod_varname, ind_name_table)
         if (ind == 0) then
            call document(subname, 'unknown external varname = ', &
                          trim(tracer_init_ext(n)%mod_varname))
            call exit_POP(sigAbort, 'stopping in ' /&
                                 &/ subname)
         end if

         if (trim(tracer_init_ext(n)%filename) /= 'unknown') &
              tracer_init_int(ind)%filename = &
              tracer_init_ext(n)%filename

         if (trim(tracer_init_ext(n)%file_varname) /= 'unknown') &
              tracer_init_int(ind)%file_varname = &
              tracer_init_ext(n)%file_varname

         if (tracer_init_ext(n)%scale_factor /= c1) &
              tracer_init_int(ind)%scale_factor = &
              tracer_init_ext(n)%scale_factor

         if (tracer_init_ext(n)%default_val /= c1) &
              tracer_init_int(ind)%default_val = &
              tracer_init_ext(n)%default_val
      end if
   end do

!-----------------------------------------------------------------------
!  process internal tracer_init array
!-----------------------------------------------------------------------

   do n = 1,tracer_cnt
      if (trim(tracer_init_int(n)%filename) == 'none' .or. &
          trim(tracer_init_int(n)%filename) == 'unknown') then
         call document(subname, 'initializing ' /&
                             &/ trim(tracer_init_int(n)%mod_varname) /&
                             &/ ' to default_val')
         do iblock = 1,nblocks_clinic
            TRACER_MODULE(:,:,:,n,curtime,iblock) =  &
               tracer_init_int(n)%default_val
         enddo
      else
         call document(subname, 'initializing ' /&
                             &/ trim(tracer_init_int(n)%mod_varname) /&
                             &/ ' with ' /&
                             &/ trim(tracer_init_int(n)%file_varname) /&
                             &/ ' from ' /&
                             &/ trim(tracer_init_int(n)%filename))

         call read_field(tracer_init_int(n)%file_fmt,        &
                         tracer_init_int(n)%filename,        &
                         tracer_init_int(n)%file_varname,    &
                         TRACER_MODULE(:,:,:,n,curtime,:))

         do iblock=1,nblocks_clinic
            TRACER_MODULE(:,:,:,n,curtime,iblock) = &
               TRACER_MODULE(:,:,:,n,curtime,iblock)*tracer_init_int(n)%scale_factor
            where (TRACER_MODULE(:,:,:,n,curtime,iblock) < c0) &
               TRACER_MODULE(:,:,:,n,curtime,iblock) = c0
         end do

         if (my_task == master_task) then
            write(stdout,blank_fmt)
            write(stdout,'(a12,a)') ' file read: ', &
               trim(tracer_init_int(n)%filename)
         endif

      end if
      do iblock=1,nblocks_clinic
         TRACER_MODULE(:,:,:,n,oldtime,iblock) = &
            TRACER_MODULE(:,:,:,n,curtime,iblock)
      enddo
   end do

   deallocate(tracer_init_int)

!-----------------------------------------------------------------------
!EOC

 end subroutine file_read_tracer_block

!***********************************************************************
!BOP
! !IROUTINE: read_field_2D
! !INTERFACE:

 subroutine read_field_2D(fmt, filename, fieldname, FIELD, record_length)

! !DESCRIPTION:
!  read 2D field from a file
!  Assumes the field is (nx_global,ny_global), cell centered, and scalar.
!  For binary files, the default external precision is double precision.
!  This can be overridden by passing the desired precision into record_length.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

   character (*), intent(in) ::  &
      fmt,                 & ! format (bin or nc)
      filename,            & ! file to read from
      fieldname              ! field to be read

   integer(int_kind), intent(in), optional :: &
      record_length          ! record length type for binary files

! !INPUT/OUTPUT PARAMETERS:

   real(r8), dimension(:,:,:), intent(inout), target :: &
      FIELD                  ! field to be read in

!EOP
!BOC
!-----------------------------------------------------------------------
!  local variables
!-----------------------------------------------------------------------

   character(*), parameter :: &
      subname = 'passive_tracer_tools:read_field_2D'

   integer(int_kind) :: &
      record_length_loc    ! record length type for binary files

   type (io_field_desc) :: &
      FIELD_DESC           ! IO field descriptors for FIELD

   type (datafile) :: &
      restart_file         ! io file descriptor

   type (io_dim) :: &
      i_dim, j_dim         ! dimension descriptors

!-----------------------------------------------------------------------

   call document(subname, 'reading ' /&
                       &/ trim(fieldname) /&
                       &/ ' from ' /&
                       &/ trim(filename))

   if (present(record_length)) then
      record_length_loc = record_length
   else
      record_length_loc = rec_type_dbl
   endif

   restart_file =                                     &
      construct_file(fmt,                             &
                     full_name=trim(filename),        &
                     record_length=record_length_loc, &
                     recl_words=nx_global*ny_global)

   call data_set(restart_file, 'open_read')

   i_dim = construct_io_dim('i', nx_global)
   j_dim = construct_io_dim('j', ny_global)

   FIELD_DESC =                                       &
      construct_io_field(trim(fieldname),             &
                         dim1=i_dim,                  &
                         dim2=j_dim,                  &
                         d2d_array = FIELD)

   call data_set (restart_file, 'define', FIELD_DESC)

   call data_set (restart_file, 'read', FIELD_DESC)

   call destroy_io_field (FIELD_DESC)

   call data_set (restart_file, 'close')

   call destroy_file (restart_file)

!-----------------------------------------------------------------------
!EOC

 end subroutine read_field_2D

!***********************************************************************
!BOP
! !IROUTINE: read_field_3D
! !INTERFACE:

 subroutine read_field_3D(fmt, filename, fieldname, FIELD, record_length)

! !DESCRIPTION:
!  read 3D field from a file
!  Assumes the field is (nx_global,ny_global), cell centered, and scalar.
!  The length of the 3rd dimension is determined by the dimension of FIELD.
!  For binary files, the default external precision is double precision.
!  This can be overridden by passing the desired precision into record_length.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

   character (*), intent(in) ::  &
      fmt,                 & ! format (bin or nc)
      filename,            & ! file to read from
      fieldname              ! field to be read

   integer(int_kind), intent(in), optional :: &
      record_length          ! record length type for binary files

! !INPUT/OUTPUT PARAMETERS:

   real(r8), dimension(:,:,:,:), intent(inout), target :: &
      FIELD                  ! field to be read in

!EOP
!BOC
!-----------------------------------------------------------------------
!  local variables
!-----------------------------------------------------------------------

   character(*), parameter :: &
      subname = 'passive_tracer_tools:read_field_3D'

   integer(int_kind) :: &
      record_length_loc    ! record length type for binary files

   type (io_field_desc) :: &
      FIELD_DESC           ! IO field descriptors for FIELD

   type (datafile) :: &
      restart_file         ! io file descriptor

   type (io_dim) :: &
      i_dim, j_dim, k_dim  ! dimension descriptors

!-----------------------------------------------------------------------

   call document(subname, 'reading ' /&
                       &/ trim(fieldname) /&
                       &/ ' from ' /&
                       &/ trim(filename))

   if (present(record_length)) then
      record_length_loc = record_length
   else
      record_length_loc = rec_type_dbl
   endif

   restart_file =                                     &
      construct_file(fmt,                             &
                     full_name=trim(filename),        &
                     record_length=record_length_loc, &
                     recl_words=nx_global*ny_global)

   call data_set(restart_file, 'open_read')

   i_dim = construct_io_dim('i', nx_global)
   j_dim = construct_io_dim('j', ny_global)
   k_dim = construct_io_dim('k', size(FIELD,3))

   FIELD_DESC =                                       &
      construct_io_field(trim(fieldname),             &
                         dim1=i_dim,                  &
                         dim2=j_dim,                  &
                         dim3=k_dim,                  &
                         d3d_array = FIELD)

   call data_set (restart_file, 'define', FIELD_DESC)

   call data_set (restart_file, 'read', FIELD_DESC)

   call destroy_io_field (FIELD_DESC)

   call data_set (restart_file, 'close')

   call destroy_file (restart_file)

!-----------------------------------------------------------------------
!EOC

 end subroutine read_field_3D

!***********************************************************************

 end module passive_tracer_tools

!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
